package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.MessageConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import com.sky.exception.BaseException;
import org.aspectj.bridge.Message;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * packageName com.sky.aspect
 *
 * @author fenglai
 * @version JDK 11
 * @className AutoFillAspect
 * @date 2023/12/6
 * @description TODO
 */

@Aspect
@Component
public class AutoFillAspect {

    @Pointcut("execution(* com.sky.mapper.*.*(..))&&@annotation(com.sky.annotation.AutoFill)")
    public void autoFill() {
    }


    @Before("autoFill()")
    public void autoFillAspect(JoinPoint joinPoint) {

        //自动填充实现步骤
        //首先获得形参对象 也就是实体类 做了约定 自动填充对象的参数第一个都必须是实体类
        Object[] args = joinPoint.getArgs();
        Object arg = args[0];

        //接着 获得类上的注解 以及它的value方法 用来判断是什么方法 因为填充的方法有多种
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        AutoFill annotation = method.getAnnotation(AutoFill.class);
        OperationType value = annotation.value();

        //接下来就是通过反射将值填充 或者说可以获得set方法

        try {
            Field createTime = arg.getClass().getDeclaredField("createTime");
            Field createUser = arg.getClass().getDeclaredField("createUser");
            Field updateTime = arg.getClass().getDeclaredField("updateTime");
            Field updateUser = arg.getClass().getDeclaredField("updateUser");

            //接下来判断被切入点命中的目标对象上的注解 因为是用注解的value来判断注解的方法
            if (value == OperationType.UPDATE) {
                updateTime.trySetAccessible();
                updateTime.set(arg, LocalDateTime.now());
                updateUser.trySetAccessible();
                updateUser.set(arg, BaseContext.getCurrentId());
            } else {
                createTime.trySetAccessible();
                createTime.set(arg, LocalDateTime.now());
                createUser.trySetAccessible();
                createUser.set(arg, BaseContext.getCurrentId());
                updateTime.trySetAccessible();
                updateTime.set(arg, LocalDateTime.now());
                updateUser.trySetAccessible();
                updateUser.set(arg, BaseContext.getCurrentId());
            }
        } catch (Exception exception) {
            throw new BaseException(MessageConstant.AUTO_FILL_FAILED);
        }
    }

}